package org.linlinjava.litemall.web.service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.linlinjava.litemall.core.util.AdminCouponDateUtil;
import org.linlinjava.litemall.core.util.ResponseUtil.Response;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.dao.LitemallCouponMapper;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.DateTimeUtil;
import org.linlinjava.litemall.db.util.LocalDateTimeUtils;
import org.linlinjava.litemall.db.util.OrderHandleOption;
import org.linlinjava.litemall.db.util.OrderStatusUtil;
import org.linlinjava.litemall.web.dto.AdminCouponDTO;
import org.linlinjava.litemall.web.util.WebResponseEnum;
import org.linlinjava.litemall.web.vo.OrderDetailResponseVO;
import org.linlinjava.litemall.web.vo.WebMyCouponsVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import static org.linlinjava.litemall.web.util.WebResponseCode.*;


/**
 * @author ：stephen
 * @date ：Created in 2020/5/12 13:50
 * @description：pos扫码使用优惠券，一个订单仅能使用一张优惠券，使用e第二张会覆盖第一张的优惠，并且优惠券可用数量仍然会-1
 */
@Service
@RequiredArgsConstructor
public class WebCouponService {
    private final LitemallCouponService litemallCouponService;

    private final LitemallOrderService litemallOrderService;

    private final LitemallCouponUserService litemallCouponUserService;
    private final WebOrderService webOrderService;

    private final LitemallShopRegionService litemallShopRegionService;

    private final LitemallRegionService regionService;

    private final LitemallCouponMapper couponMapper;

    private final LitemallCouponUserService couponUserService;

    private final LitemallShopRegionService shopRegionService;

    private final LitemallGoodsService litemallGoodsService;

    private final LumiereCouponUserService lumiereCouponUserService;

    private final LumiereCouponStrategyService lumiereCouponStrategyService;
    private final LumiereCouponService lumiereCouponService;


    public void awardCoupon(LitemallUser user,BigDecimal amount,Integer couponType,Integer deviceNo){
        //调用充值策略
        List<LumiereCouponStrategy> couponStrategyList = lumiereCouponStrategyService.list(Wrappers.lambdaQuery(LumiereCouponStrategy.class)
                .eq(LumiereCouponStrategy::getCouponType, couponType)
                .eq(LumiereCouponStrategy::getStatus, 1));
        couponStrategyList.stream().forEach(couponStrategy -> {
            boolean contains = deviceNo!=null?Arrays.asList(couponStrategy.getRechargeGift()).contains(deviceNo):true;
            if(couponStrategy.getRechargeAmount().compareTo(amount)!=1&&contains){
                //赠送券
                long nextId = IdUtil.getSnowflake(2, 2).nextId();
                LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(couponStrategy);
                LumiereCouponUser couponUser = LumiereCouponUser.builder()
                        .userId(user.getId())
                        .strategyId(couponStrategy.getId())
                        .couponId(couponStrategy.getCouponId())
                        .startTime(localDateTimes[0])
                        .endTime(localDateTimes[1])
                        .userName(user.getUsername())
                        .code(String.valueOf(nextId))
                        .addTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .deleted(false)
                        .build();
                lumiereCouponUserService.save(couponUser);
               /* noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER, LitemallWXConstants.WX_GIFT_RECHARGE_USER_TITLE_NOTICEMAIL,
                        String.format(LitemallWXConstants.WX_GIFT_RECHARGE_USER_NOTICEMAIL,userName,order.getAmount()), userId, order);*/
            }
        });
    }

    @Transactional
    public Object use(AdminCouponDTO dto) {
        LitemallCoupon coupon = litemallCouponService.findByBarCode(dto.getBarcode());
        if (coupon == null) {
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_ERROR);
        }
        // 检查是否超期
        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(coupon.getStartTime()) || now.isAfter(coupon.getEndTime())) {
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_EXPIRE);
        }
        if(coupon.getTotal() < 0){
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_NOT_ENOUGH);
        }

        LitemallOrder order = litemallOrderService.findById(dto.getOrderId());
        if(order == null){
            return ResponseUtil.fail(WebResponseEnum.ORDER_NOT_EXIST);
        }
        if(order.getActualPrice().compareTo(coupon.getMin()) == -1){
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_ORDER);
        }
        // 检测订单是否能够使用优惠券
        OrderHandleOption handleOption = OrderStatusUtil.build(order);
        if (!handleOption.isPay()) {
            return ResponseUtil.fail(WebResponseEnum.ORDER_NOT_EXIST);
        }


       /* LitemallCouponUser couponUser = couponUserService.queryOne(userId, coupon.getId());
        //判断这张优惠券是的使用规则
        switch (coupon.getUseLimit()){
            //每年
            case 0:
                Integer useCountYear = couponUserService.queryByLimitInUse(userId,  coupon.getId(), LocalDateTimeUtils.getStartOrEndDayOfYear(null,true), LocalDateTimeUtils.getStartOrEndDayOfYear(null,false));
                //如果已使用的券数大于等于限制使用数时
                if(useCountYear>=coupon.getUseLimitNum()){
                    return null;
                };
                //每月
            case 1:
                Integer useCountMonth = couponUserService.queryByLimitInUse(userId,  coupon.getId(), LocalDateTimeUtils.getStartOrEndDayOfMonth(null,true), LocalDateTimeUtils.getStartOrEndDayOfMonth(null,false));
                //如果已使用的券数大于等于限制使用数时
                if(useCountMonth>=coupon.getUseLimitNum()){
                    return null;
                };
                //每周
            case 2:
                Integer useCountWeek = couponUserService.queryByLimitInUse(userId,  coupon.getId(), LocalDateTimeUtils.getStartOrEndDayOfWeek(null,true), LocalDateTimeUtils.getStartOrEndDayOfWeek(null,false));
                //如果已使用的券数大于等于限制使用数时
                if(useCountWeek>=coupon.getUseLimitNum()){
                    return null;
                };
                //每天
            case 3:
                Integer useCountDay= couponUserService.queryByLimitInUse(userId,  coupon.getId(), LocalDateTimeUtils.getStartOrEndDayOfDay(null,true), LocalDateTimeUtils.getStartOrEndDayOfDay(null,false));
                //如果已使用的券数大于等于限制使用数时
                if(useCountDay>=coupon.getUseLimitNum()){
                    return null;
                };
        }
        if (coupon == null || couponUser == null) {
            return ResponseUtil.fail("使用限制上线");
        }*/


        BigDecimal couponPrice = new BigDecimal(0.00);
        if(coupon.getDiscountType() == Constants.DISCOUNT_TYPE_REDUCE){
            couponPrice = coupon.getDiscount();
        }else if(coupon.getDiscountType() == Constants.DISCOUNT_TYPE_RATE){
            //优惠价格 = 订单价格 - (订单价格+原先的优惠价格)*优惠比例
            couponPrice = order.getActualPrice().subtract(order.getActualPrice().add(order.getCouponPrice()).multiply(new BigDecimal(coupon.getDiscountRate() / 100)));
        }

        LitemallOrder updater = new LitemallOrder();
        updater.setId(order.getId());
        //订单价格 = 订单价格 + 原先的优惠价格 - 后面的优惠价格
        updater.setOrderPrice(order.getGoodsPrice()
                .add(
                        order.getTaxPrice() == null ? BigDecimal.ZERO : order.getTaxPrice())
                .add(
                        order.getFreightPrice() == null ? BigDecimal.ZERO : order.getFreightPrice()));
        updater.setBindCouponId(null);
        updater.setCouponPrice(couponPrice);
        updater.setActualPrice(updater.getOrderPrice().subtract(couponPrice));
        updater.setUpdateTime(order.getUpdateTime());
        //记录使用日志
        log(coupon, order);
        //更新优惠券数量
        LitemallCoupon couponUpdate = new LitemallCoupon();
        couponUpdate.setId(coupon.getId());

        //
        couponUpdate.setTotal(coupon.getTotal()-1);
        if(litemallCouponService.updateById(couponUpdate) == 0){
            throw new RuntimeException("更新优惠券数量失败");
        }
        //更新订单
        if(litemallOrderService.updateWithOptimisticLocker(updater) == 0){
            throw new RuntimeException("更新订单失败");
        };
        return order;
    }


    /**
     * 查询代码
     *
     * @param barCode  条形码
     * @param shopId   商店id
     * @return {@link Response}<{@link LitemallCoupon}>
     */
    public Response queryByCode(String barCode,Integer shopId,List<Integer> gsIds){
        //优惠券
        if(StrUtil.isEmpty(barCode)){
            return ResponseUtil.fail("请输入code");
        }
        LumiereCouponUser lumiereCouponUser = lumiereCouponUserService.getOne(Wrappers.lambdaQuery(LumiereCouponUser.class)
                .eq(LumiereCouponUser::getCode, barCode));
        if(ObjectUtil.isNull(lumiereCouponUser)){
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_ERROR);
        }
        //检测优惠券
        if(LocalDateTime.now().isAfter(lumiereCouponUser.getEndTime())){
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_EXPIRE);
        }
        if(lumiereCouponUser.getUsedTime()!=null){
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_HAVE_USE);
        }
        LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.getById(lumiereCouponUser.getStrategyId());
        //判断使用范围 使用范围：1APP 2POS 3网站
        if(!Arrays.stream(couponStrategy.getRanges()).anyMatch(i -> i == 2)){
            return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_NOT_POS);
        }
        if((couponStrategy.getCouponType()==1||couponStrategy.getCouponType()==3||couponStrategy.getCouponType()==5)&&couponStrategy.getUseLimit()!=4){
            //判断年月周天的限制
            LocalDateTime[] locaTimeStartEnd = DateTimeUtil.getLocaTimeStartEnd(couponStrategy.getUseLimit().intValue());
            long useCount = lumiereCouponUserService.count(Wrappers.lambdaQuery(LumiereCouponUser.class)
                    .eq(LumiereCouponUser::getUserId, lumiereCouponUser.getUserId())
                    .isNotNull(LumiereCouponUser::getUsedTime)
                    .between(LumiereCouponUser::getUsedTime, locaTimeStartEnd[0], locaTimeStartEnd[1]));
            if(couponStrategy.getUseLimitNum()<=useCount){
                return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_NOT_ENOUGH);
            }
        }
        //下面写对商品、地区、菜单的限制
        //匹配限制区域
        if (couponStrategy.getAreaLimit() != null && couponStrategy.getAreaLimit() == 1 && shopId != null) {
            if (couponStrategy.getRegions() != null) {

                Integer[] regionsId = couponStrategy.getRegions();
                if (regionsId != null && regionsId.length > 0) {
                    List<LitemallShopRegion> shopRegions = shopRegionService.queryByShopIdAndRegionIds(shopId, Arrays.asList(regionsId));
                    if (shopRegions.size() == 0) {
                        return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_REGION_LIMIT);
                    }
                }
            }
        }

        if(gsIds!=null){
            //匹配 指定分类，指定商品优惠券
            Short goodType = couponStrategy.getGoodsType();
            if (goodType.equals(Constants.GOODS_TYPE_CATEGORY)) {
                Integer[] couponGoodsValue = couponStrategy.getGoodsValue();

                //通过商品查询分类
                List<LitemallGoods> gs = litemallGoodsService.findByIds(gsIds);
                List<Integer> cateIds = gs.stream().map(LitemallGoods::getCategoryId).distinct().collect(Collectors.toList());

                boolean flag = false;
                for (int i = 0; i < cateIds.size(); i++) {
                    for (int j = 0; j < couponGoodsValue.length; j++) {
                        if (cateIds.get(i).equals(couponGoodsValue[j])) {
                            flag = true;
                        }
                    }
                }

                if (!flag) {
                    return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_GOODS_LIMIT);
                }
            } else if (goodType.equals(Constants.GOODS_TYPE_ARRAY)) {
                Integer[] couponGoodsValue = couponStrategy.getSelectGoods();
                boolean flag = false;
                for (int i = 0; i < gsIds.size(); i++) {
                    for (int j = 0; j < couponGoodsValue.length; j++) {
                        if (gsIds.get(i).equals(couponGoodsValue[j])) {
                            flag = true;
                        }
                    }
                }

                if (!flag) {
                    return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_GOODS_LIMIT);
                }
            }
        }

        LumiereCoupon coupon = lumiereCouponService.getById(lumiereCouponUser.getCouponId());
        WebMyCouponsVO webMyCouponsVO = WebMyCouponsVO.builder()
                .couponName(couponStrategy.getName())
                .couponType(couponStrategy.getCouponType())
                .pictureUrl(coupon.getPictureUrl())
                .descr(coupon.getDescr())
                .startTime(lumiereCouponUser.getStartTime())
                .endTime(lumiereCouponUser.getEndTime())
                .ranges(couponStrategy.getRanges())
                .discountType(couponStrategy.getDiscountType())
                .discountRate(couponStrategy.getDiscountRate())
                .discount(couponStrategy.getDiscount())
                .min(couponStrategy.getMin())
                .useLimit(couponStrategy.getUseLimitNum())
                .useLimitNum(couponStrategy.getUseLimitNum())
                .useInstruction(couponStrategy.getUseInstruction())
                .code(lumiereCouponUser.getCode())
                .addTime(lumiereCouponUser.getAddTime())
                .build();
        return ResponseUtil.ok(webMyCouponsVO);
    }

    public Response<LitemallCoupon> queryByOrderId(Integer orderId){
        LitemallOrder order = null;
        if(orderId != null){
            order = litemallOrderService.findById(orderId);
        }

        LitemallCoupon coupon = null;
        if(order != null ){
            if(order.getBindCouponId() != null){
               coupon =  litemallCouponService.findById(order.getBindCouponId());
            }
        }

        return ResponseUtil.ok(coupon);
    }

    public Response<OrderDetailResponseVO> bind(Integer id, Integer orderId, boolean isBind){
        LitemallCoupon coupon = null;
        if(isBind){
            LitemallCouponExample example = new LitemallCouponExample();
            example.or().andIdEqualTo(id).andDeletedEqualTo(false);
            List<LitemallCoupon> couponList = couponMapper.selectByExample(example);
            if(couponList.size()>1){
                return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_NOT_POS);
            }
            coupon=couponList.size()==0?null:couponList.get(0);
//            coupon = litemallCouponService.findByBarCode(barCode);
            if (coupon == null) {
                return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_ERROR);
            }

            // 检查是否超期
            LocalDateTime now = LocalDateTime.now();
            if(coupon.getStartTime() != null && coupon.getEndTime() != null){
                if (now.isBefore(coupon.getStartTime()) || now.isAfter(coupon.getEndTime())) {
                    return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_EXPIRE);
                }
            }
            if(coupon.getTotal() < 0){
                return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_NOT_ENOUGH);
            }
        }

        LitemallOrder order = litemallOrderService.findById(orderId);
        if(order == null){
            return ResponseUtil.fail(WebResponseEnum.ORDER_NOT_EXIST);
        }

        if(coupon != null){
            if(order.getActualPrice().compareTo(coupon.getMin()) == -1){
                return ResponseUtil.fail(WebResponseEnum.COUPON_BARCODE_ORDER);
            }
        }
        // 检测订单是否能够使用优惠券
        BigDecimal couponPrice = new BigDecimal(0.00);
        if(isBind){
            OrderHandleOption handleOption = OrderStatusUtil.build(order);
            if (!handleOption.isPay()) {
                return ResponseUtil.fail(WebResponseEnum.ORDER_NOT_EXIST);
            }

            if(coupon.getDiscountType() == Constants.DISCOUNT_TYPE_REDUCE){
                couponPrice = coupon.getDiscount();
            }else if(coupon.getDiscountType() == Constants.DISCOUNT_TYPE_RATE){
                //优惠价格 = 订单价格 * 优惠比例
                couponPrice = order.getActualPrice().multiply(new BigDecimal(coupon.getDiscountRate().intValue()).divide(new BigDecimal(100)));
                //优惠价格 = 订单价格 - (订单价格+原先的优惠价格)*优惠比例
                // couponPrice = order.getActualPrice().subtract(order.getActualPrice().add(order.getCouponPrice()).multiply(new BigDecimal(coupon.getDiscountRate().intValue()).divide(new BigDecimal(100))));
            }
        }


        LitemallOrder updater = new LitemallOrder();
        updater.setId(order.getId());
        //订单价格 = 订单价格 + 原先的优惠价格 - 后面的优惠价格

        if(isBind){
            updater.setOrderPrice(order.getOrderPrice().subtract(couponPrice));
//            updater.setBindCouponId(coupon.getId());
        }else{
            updater.setOrderPrice(order.getGoodsPrice()
                                  .add(
                                   order.getTaxPrice() == null ? BigDecimal.ZERO : order.getTaxPrice())
                                  .add(
                                  order.getFreightPrice() == null ? BigDecimal.ZERO : order.getFreightPrice())
                                  .subtract(couponPrice));
            updater.setBindCouponId(null);
        }
        updater.setBindCouponId(coupon != null ? coupon.getId() : 0);
        updater.setCouponPrice(couponPrice);
        updater.setActualPrice(updater.getOrderPrice());
        updater.setUpdateTime(order.getUpdateTime());

        //更新订单
        if(litemallOrderService.updateWithOptimisticLocker(updater) == 0){
            throw new RuntimeException("更新订单失败");
        }

        Response<OrderDetailResponseVO> res = webOrderService.detail(orderId);
        res.getData().setBarCode(coupon != null ? coupon.getBarCode() : null);
        return res;
    }

    /**
     * 记录日志
     * @param coupon
     * @param order
     */
    private void log(LitemallCoupon coupon, LitemallOrder order) {
        LitemallCouponUser couponUser = new LitemallCouponUser();
        couponUser.setUsedTime(LocalDateTime.now());
        couponUser.setCouponId(coupon.getId());
        couponUser.setOrderId(order.getId());
        couponUser.setStatus(Constants.COUPON_STATUS_USED);
        //这里用户id不能为空，设置为0
        couponUser.setUserId(0);
        litemallCouponUserService.add(couponUser);
    }


    /**
     * 得到车间区域id
     *
     * @param shopId 商店id
     * @return {@link Integer}
     */
    private Integer getShopRegionId(Integer shopId) {
        List<LitemallShopRegion> litemallShopRegions = litemallShopRegionService.queryByShopId(shopId);
        if(!CollectionUtils.isEmpty(litemallShopRegions)) {
            for (LitemallShopRegion litemallShopRegion : litemallShopRegions) {
                LitemallRegion litemallRegion = regionService.findById(litemallShopRegion.getRegionId());
                if(Constants.REGION_TYPE_CITY == litemallRegion.getType()) {
                    return litemallShopRegion.getRegionId();
                }
            }
        }
        return null;
    }
}
